from abc import ABCMeta, abstractmethod


# 抽象 观察者 也就是订阅者
class Observer(metaclass=ABCMeta):
    @abstractmethod
    def update(self, notice):  # notice 参数是一个 Notice 类的对象
        pass


# 抽象 发布者
class Notice:
    def __init__(self):
        self.observers = []  # 初始化观察者列表

    # 绑定观察者到发布者的列表中
    def attach(self, obs):
        self.observers.append(obs)

    # 从发布者的观察者列表中移除观察者
    def detach(self, obs):
        self.observers.remove(obs)

    # 自动通知全部观察者，推送最新信息
    def notify(self):
        for obs in self.observers:
            obs.update(self)


# 具体的发布者-公司公告中心HR
class StaffNotice(Notice):
    def __init__(self, company_info=None):
        super().__init__()  # 调用父类构造函数
        self.__company_info = company_info  # 公司信息，默认为 None

    @property
    def company_info(self):
        return self.__company_info  # 获取公司信息

    @company_info.setter
    def company_info(self, info):
        self.__company_info = info  # 设置公司信息
        self.notify()  # 设置公司信息后，自动推送通知给所有观察者


# 具体的订阅者-公司员工
class Staff(Observer):
    def __init__(self):
        self.company_info = None  # 初始化时员工对公司信息的了解为 None

    def update(self, notice):
        self.company_info = notice.company_info  # 更新员工对公司信息的了解


# 客户端代码使用

notice = StaffNotice("初始公司信息")  # 创建一个公司公告中心，初始信息为 "初始公司信息"
s1 = Staff()  # 创建 1 号员工
s2 = Staff()  # 创建 2 号员工

notice.attach(s1)  # 将 1 号员工添加到公告中心的观察者列表
notice.attach(s2)  # 将 2 号员工添加到公告中心的观察者列表
notice.company_info = '公司发布了一个消息通知：明天工作'  # 更新公司信息，触发通知
print(s1.company_info)  # 输出：公司发布了一个消息通知：明天工作
print(s2.company_info)  # 输出：公司发布了一个消息通知：明天工作

notice.detach(s2)  # 2 号员工取消订阅
notice.company_info = '公司发布了一个消息通知：明天休息'  # 再次更新公司信息，触发通知
print(s1.company_info)  # 输出：公司发布了一个消息通知：明天休息
print(s2.company_info)  # 输出：公司发布了一个消息通知：明天工作 （因为 s2 已经取消订阅）
